/*
 *
 * C++ MaJiang for 血流红中
 *
 * TuyooGame, 2021
 * zhouxin@tuyoogame.com
 *
 */
#include "xueliuhz/fan.h"

using namespace std;

void 
assignCPG(MJ_CPG *cpg, uint8_t tile,
               uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4, 
               int8_t seat, MJ_CPG_TYPE t, MJ_CPG_SUBTYPE st) {
    cpg->tile = tile;
    cpg->com[0] = c1;
    cpg->com[1] = c2;
    cpg->com[2] = c3;

    //对于3张吃碰牌，com[3]一定填0
    if(t==GANG)
        cpg->com[3] = c4;
    else 
        cpg->com[3] = 0;

    cpg->type = t;
    cpg->from_seat = seat;
    cpg->subtype = st;
}

bool 
assignMFI(MJ_FX_INFO *mfi, 
          vector<uint8_t> &hands, vector<uint8_t> &lz, uint8_t now_tile, 
          MJ_TILE_TYPE que, MJ_CPG_INFO *cpg, 
          MJ_HU_TYPE ht, const vector<uint8_t> &pool) {

    //检查参数
    //不包含cpg的手牌，不能超过14张，至少1张
    if(hands.size()>14 or hands.size()<1)
        return false;
    if(lz.size()!=1)
        return false;
    if(lz[0]!=35)
        return false;
    if(now_tile>35 or now_tile<0) 
        return false;
    if(que>TONG or que<0) 
        return false;
    if(cpg) {
        if(cpg->count>4 or cpg->count<0)
            return false;
    }

    mfi->ti_hand.assign(hands, lz);
    if(now_tile) hands.push_back(now_tile);

    //如果now_tile为0，实际上ti_hand和ti_hand_now是一样的...
    if(!mfi->ti_hand_now.assign(hands, lz))
        return false;

    vector<uint8_t> v43 = hands;

    //添加cpg...
    if(cpg) {
        for(uint8_t i=0; i<cpg->count; i++) {
            for(uint8_t j=0; j<4; j++)
                if(cpg->cpgs[i].com[j])
                    hands.push_back(cpg->cpgs[i].com[j]);
            for(uint8_t j=0; j<3; j++)
                v43.push_back(cpg->cpgs[i].com[j]);
        }
    }

    if(!mfi->ti_all.assign(hands, lz)) 
        return false;
    if(!mfi->ti_all_gang4to3.assign(v43, lz)) 
        return false;

    mfi->now_tile = now_tile;
    mfi->que = que;
    mfi->cpg = *cpg;

    mfi->hutype = ht;
    mfi->tile_pool = pool;

    return true;
}

//手牌是否可以点炮胡或者自摸胡
bool 
hasHu(vector <uint8_t> ts, uint8_t tile) {
    //中间运算用到的Tiles实例
    static Tiles _ti_hu1;    
    static Tiles _ti_hu2; 

    //if(ts.size()==10 && tile==1 && ts[9]==35 && ts[0]==11 && ts[3]==6)
    //    printf("For DEBUG BreakPoint...\n");

    set<uint8_t> tss(ts.begin(), ts.end());

    //手牌只有红中的情况...
    if(tss.size() == 1 and ts[0]==35)
        return tile==35 or tile==0;

    //手上已有4张，外面没有了...
    int num = count(ts.begin(), ts.end(), tile);
    if(num==4 and tile!=35)
        return false;

    if(tile) ts.push_back(tile);
    vector<uint8_t> lz {35};
    _ti_hu1.assign(ts, lz);
    MJ_COUNTER *cnz = &_ti_hu1.counter_noz;
    MJ_COUNTER *cz = &_ti_hu1.counter_z;

    //七对（红中不能单吊任意牌)
    if(ts.size() == 14) {
        int no_pair_len = 0;
        for(uint8_t i=0; i<cnz->bucket_len; i++) {
            if(cnz->bucket[i]%2==1)
                no_pair_len++;
        }
        if(no_pair_len <= _ti_hu1.counter[JIAN].n) {
            if((tile>0 and cnz->bucket[tile-1]>1) || _ti_hu1.isLaiZi(tile) )
                return true;
        }
    }

    if(_ti_hu1.isHu()) {
        if(_ti_hu1.counter[JIAN].n==0 or num>0)
            return true;
        if(tile) tss.insert(tile);
        //防止红中单吊没有关系的牌...
        for(auto t : tss) {
            uint8_t tcount = 0;
            if(t<30) tcount = cnz->bucket[t-1];
            else tcount = cz->bucket[t-30-1];
            if(t==tile and tcount<=1) 
                continue;
            vector<uint8_t> tmpv = ts;
            if(tcount>1) {
                remove_nv(tmpv, t, 2);
            } else {
                remove_nv(tmpv, t, 1);
                remove_nv(tmpv, 35, 1);
            }
            tmpv.push_back(31);
            tmpv.push_back(31);
            _ti_hu2.assign(tmpv, lz);
            if(_ti_hu2.isHu())
                return true;
        }
    }
    return false;
}

//ts参数修改为复制传递，避免将传入的手牌修改
bool
hasHu_bu(vector<uint8_t> ts, uint8_t bu_count, uint8_t bu_tile, uint8_t tile) {
    for(uint8_t n=0; n<bu_count; n++)
        ts.push_back(bu_tile);
    return hasHu(ts, tile);
}

//多个函数中用到，抽成一个函数...
uint64_t 
_hand_nt(vector<uint8_t> & hand, uint8_t & nowtile, uint8_t ke) {
    if(findv(hand, ke)) {
        remove_nv(hand, ke, 1);
    } else if(ke == nowtile) {
        nowtile = 0;
    } else if(findv(hand, 35)) {
        remove_nv(hand, 35, 1);
    } else if(nowtile == 35) {
        nowtile = 0;
    } else {
        return 0;
    }
    return 1;
}

//血流红中玩法不会出现5张的牌，兼容其他玩法
uint64_t
getFanGenCount(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_all;
    return ti->count_all[4] + ti->count_all[5];
}

//不是七对返回0,普通七对返回1,龙七对返回10，双龙返回20，三龙返回30
uint64_t
fx_QiDui(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand_now;
    if(ti->tiles_len != 14) return -1;
    uint8_t lzcount = ti->laizi_count;
    uint8_t needlz = ti->count_noz[1] + ti->count_noz[3];
    if(needlz > lzcount) return 0;
    uint8_t ret = ti->count_noz[4] + ti->count_noz[3] + (lzcount - needlz) / 2;
    return ret==0 ? 1 : ret*10;
}

//一条龙返回1，否则返回0
uint64_t 
fx_YiTiaoLong(MJ_FX_INFO *m) {
    if(!m) return 0;

    Tiles *ti = &m->ti_hand_now;
    uint8_t lzcount;
    const vector<vector<uint8_t>> yitiaolong {{1,2,3}, {4,5,6}, {7,8,9}};
    vector<vector<uint8_t>> tmp_ytl {};
    vector<uint8_t> hands {};
    vector<uint8_t> cphands {};
    vector<uint8_t> cpos {};

    for(int color=WAN; color<=TONG; color++) {
        hands.clear();
        ti->getHandsNoZi(hands);
        ti->getHandsNoZi(cphands);
        lzcount = ti->laizi_count;
        tmp_ytl = yitiaolong;
        for(auto tile : cphands) {
            if(tile/10!=color) continue;
            for(auto &oneshun : tmp_ytl) {
                cpos = oneshun;
                for(auto t : cpos) {
                    if(t==tile%10) {
                        remove_nv(oneshun, t, 1);
                        remove_nv(hands, tile, 1);
                    }
                }
            }
        }
        uint8_t remain = 0;
        for(auto oneshun : tmp_ytl) {
            remain += oneshun.size();
        }
        if(lzcount < remain) continue;
        //去掉一条龙如果还能胡，就是一条龙...
        return hasHu_bu(hands, lzcount-remain, 35, 0) ? 1 : 0;
    }
    return 0;
}

//门清返回1，否则返回0
uint64_t
fx_MenQing(MJ_FX_INFO *m) {
    if(!m) return 0;
    MJ_CPG_INFO *c = &m->cpg;
    for(int i=0; i<c->count; i++) {
        if(c->cpgs[i].type == GANG and c->cpgs[i].subtype == AN_GANG )
            continue;
        else
            return 0;
    }
    return 1;
}

//全求人返回1，否则返回0
//红中血流没有这个番型...
uint64_t
fx_QuanQiuRen(MJ_FX_INFO *m) {
    if(!m) return 0;
    MJ_CPG_INFO *c = &m->cpg;
    if(c->count!=4) return 0;
    for(int i=0; i<c->count; i++) {
        if(c->cpgs[i].type == GANG and c->cpgs[i].subtype == AN_GANG )
            return 0;
    }
    return 1;
}

//断幺九返回1，否则返回0
uint64_t
fx_DuanYaoJiu(MJ_FX_INFO *m) { 
    if(!m) return 0; 
    Tiles *ti = &m->ti_all; 
    uint8_t *bkt = ti->counter_noz.bucket; 
    uint8_t cnt = bkt[0]+bkt[8]+bkt[10]+bkt[18]+bkt[20]+bkt[28];
    return cnt ? 0 : 1;
}

//18罗汉返回1，否则返回0
uint64_t
fx_ShiBaLuoHan(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_all;
    return ti->tiles_len==18;
}

//对对胡返回1，否则返回0
uint64_t
fx_DuiDuiHu(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand_now;
    uint8_t needlz = ti->count_noz[1]*2 + ti->count_noz[2] + ti->count_noz[4]*2;
    if(needlz-1 > ti->laizi_count) 
        return 0;
    return 1;
}

uint64_t
fx_PengPengHu(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand;
    uint8_t nt = m->now_tile;
    vector<uint8_t>hands {};
    ti->getHands(hands);
    if(nt!=35 and !findv(hands, nt))
        return 0;
    if(fx_DuiDuiHu(m))
        return 1;
    return 0;
}

uint64_t
fx_JueZhang(MJ_FX_INFO *m) {
    if(!m) return 0;
    return 0;
}

//金钩吊返回1，否则返回0
uint64_t
fx_JinGouDiao(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand_now;
    return ti->tiles_len==1;
}

//清一色返回1，否则返回0
uint64_t
fx_QingYiSe(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_all;
    uint8_t colors[3] {0, 0, 0};
    for(uint8_t i=WAN; i<=TONG; i++) 
        if(ti->counter[i].n>0) colors[i]=1;
    if((colors[WAN]+colors[TIAO]+colors[TONG]) == 1)
        return 1;
    return 0;
}

//258返回1，否则返回0
uint64_t
fx_258(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_all;
    uint8_t total = 0;
    for(uint8_t i=WAN; i<=TONG; i++) {
        uint8_t *bkt = ti->counter[i].bucket;
        vector<uint8_t> no258 { 0, 2, 3, 5, 6, 8 };
        for(uint8_t j=0; j<no258.size(); j++) 
            total+=bkt[no258[j]];
    }
    if(total) return 0;
    return 1;
}

uint64_t
fx_JiangDui(MJ_FX_INFO *m) {
    if(!m) return 0;
    if(fx_DuiDuiHu(m) and fx_258(m))
        return 1;
    return 0;
}

uint64_t 
fx_ZhuoWuKui(MJ_FX_INFO *m) {
    if(!m) return 0;
    if(m->now_tile!=5 and m->now_tile!=35)
        return 0;
    //修复bug，判断kan时，不破坏m
    MJ_FX_INFO cpm;
    vector<uint8_t> ts {};
    m->ti_hand.getHands(ts);
    vector<uint8_t> lz {35};
    assignMFI(&cpm, ts, lz, 5, m->que, &m->cpg, m->hutype);
    int8_t ret = fx_Kan(&cpm);
    if(ret)
        return 1;
    return 0;
}

//12,13,14,16,18
uint64_t
fx_LvYiSe(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_all;
    uint8_t *bkt = ti->counter_noz.bucket;
    vector<uint8_t> nolv {0,1,2,3,4,5,6,7,8,10,14,16,18,19,20,21,22,23,24,25,26,27,28};
    uint8_t total = 0;
    for(uint8_t i=0; i<nolv.size(); i++) 
        total+=bkt[nolv[i]];
    if(total!=0) return 0;
    ti = &m->ti_hand_now;
    uint8_t lzcount = ti->laizi_count;
    if(lzcount!=0){
        uint8_t liutiao = ti->counter_noz.bucket[16 - 1];
        if(liutiao==0) return 1;
        vector<uint8_t> hands {};
        //非字牌去掉6条，放到hands里
        ti->getHandsNoZi(hands, 16);
        uint8_t mod_liu = liutiao>3 ? liutiao%3 : liutiao;
        uint8_t j;
        //消耗癞子
        for(j=0; j<3-mod_liu; j++) {
            if(lzcount>0)
                lzcount--;
            else
                break;
        }
        //如果没有走break
        if(j==3-mod_liu) 
            if(hasHu_bu(hands, lzcount, 35, 0))
                return 1;
        //恢复癞子个数
        lzcount = ti->laizi_count;
        if(mod_liu<=2) {
            //消耗癞子
            for(j=0; j<2-mod_liu; j++) {
                if(lzcount>0)
                    lzcount--;
                else
                    break;
            }
            //如果没有走break
            if(j==2-mod_liu) {
                if(hasHu_bu(hands, 2, 1, 0))
                    return 1;
            }
        }
        return 0;
    }
    return 1;
}

uint64_t
fx_JiuLianBaoDeng(MJ_FX_INFO *m) {
    if(fx_QingYiSe(m)==0) return 0;

    Tiles *ti = &m->ti_hand_now;

    MJ_COUNTER *cnz = &ti->counter_noz;
    vector<uint8_t> new_hand {};
    for(uint8_t i=0; i<cnz->bucket_len; i++) {
        uint8_t tcnt = cnz->bucket[i];
        if(tcnt>0) {
            for(uint8_t o=0; o<tcnt; o++)
                new_hand.push_back((i+1)%10); 
        }
    }
    uint8_t lzcount = ti->laizi_count;

    vector<uint8_t> bao_deng {1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9};
    for(uint8_t i=0; i<13; i++) {
        uint8_t t = bao_deng[i];
        if(!findv(new_hand, t)) {
            if(lzcount==0) 
                return 0;
            lzcount--;
            continue;
        }
        remove_nv(new_hand, t, 1);
    }
    return 1;
}

uint64_t 
fx_LianQiDui(MJ_FX_INFO *m) {
    if(fx_QiDui(m)==0) return 0;
    if(fx_QingYiSe(m)==0) return 0;

    Tiles *ti = &m->ti_hand_now;

    MJ_COUNTER *cnz = &ti->counter_noz;
    uint8_t lzcount = ti->laizi_count;

    uint8_t f=0;
    for(uint8_t i=0; i<cnz->bucket_len; i++) {
        uint8_t tcnt = cnz->bucket[i];
        if(tcnt>0) {
            f = i+1;
            break;
        }
    }
    vector<uint8_t> lqd {};
    for(uint8_t i=0; i<7; i++) {
        lqd.push_back(f+i);
        lqd.push_back(f+i);
    }
    for(uint8_t i=0; i<ti->tiles_len; i++) {
        uint8_t t = ti->tiles[i];
        if(t==35) continue;
        if(!findv(lqd, t))
           return 0;
        remove_nv(lqd, t, 1);
    }
    if(lqd.size() != lzcount) 
        return 0;
    return 1;
}

uint64_t 
fx_DaiYaoJiu(MJ_FX_INFO *m) {
    if(!m) return 0;

    Tiles *ti = &m->ti_hand_now;

    MJ_CPG_INFO *c = &m->cpg;
    set<uint8_t> yaojiu {1,11,21,9,19,29,35};
    for(int i=0; i<c->count; i++) {
        if(c->cpgs[i].type == GANG or c->cpgs[i].type == PENG )
            if(yaojiu.find(c->cpgs[i].tile) == yaojiu.end())
                return 0;
    }
    uint8_t lzcount = ti->laizi_count;
    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    for(uint8_t i=0; i<hands.size(); i++) {
        uint8_t dian = hands[i]%10;
        if(dian>3 and dian<7)
            return 0;
    }
    uint8_t yj[6] {1,11,21,9,19,29};
    for(uint8_t i=0; i<6; i++) {
        uint8_t one = yj[i];
        uint8_t two = one % 10 == 1 ? one+1 : one-1;
        uint8_t thr = one % 10 == 1 ? one+2 : one-2;
        while(findv(hands, one) and findv(hands, two) and findv(hands, thr)) {
            remove_nv(hands, one, 1);
            remove_nv(hands, two, 1);
            remove_nv(hands, thr, 1);
        }
    }

    vector<uint8_t> no_yaojiu {};
    for(uint8_t i=0; i<hands.size(); i++) {
        if(yaojiu.find(hands[i])!=yaojiu.end())
            continue;
        no_yaojiu.push_back(hands[i]);
    }

    while(no_yaojiu.size()!=0) {
        uint8_t tile = no_yaojiu.back();
        no_yaojiu.pop_back();
        uint8_t start = tile%10<4 ? tile/10*10+1 : tile/10*10+7;
        for(uint8_t i=0; i<3; i++) {
            uint8_t tmp = start + i;
            if(findv(hands, tmp)) {
                remove_nv(hands, tmp, 1);
                if(findv(no_yaojiu, tmp) and tmp!=tile)
                    remove_nv(no_yaojiu, tmp, 1);
            } else {
                if(lzcount>0) lzcount--;
                else return 0;
            }
        }
    }
    return hasHu_bu(hands, lzcount, 35, 0) ? 1 : 0;
}

uint64_t 
fx_QuanYaoJiu(MJ_FX_INFO *m) {
    if(!m) return 0;
    MJ_CPG_INFO *c = &m->cpg;
    set<uint8_t> yaojiu {1,11,21,9,19,29,35};
    for(int i=0; i<c->count; i++) {
        if(c->cpgs[i].type == GANG or c->cpgs[i].type == PENG )
            if(yaojiu.find(c->cpgs[i].tile) == yaojiu.end())
                return 0;
    }

    Tiles *ti = &m->ti_hand_now;

    uint8_t lzcount = ti->laizi_count;
    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    for(uint8_t i=0; i<hands.size(); i++) {
        uint8_t dian = hands[i]%10;
        if(dian>3 and dian<7)
            return 0;
    }
    set<uint8_t> yj {1,11,21,9,19,29};
    for(uint8_t i=0; i<hands.size(); i++) {
        if(yj.find(hands[i])!=yj.end())
            continue;
        return 0;
    }
    uint8_t needlz = ti->count_noz[1] + ti->count_noz[3];
    if(needlz <= lzcount)
        return 1;
    else {
        needlz = ti->count_noz[1]*2 + ti->count_noz[2] + ti->count_noz[4]*2;
        if(needlz <= lzcount+1)
            return 1;
    }
    return 0;
}

uint64_t 
hasAnKe(MJ_FX_INFO *m, uint8_t kes) {
    //printf("CALL hasAnKe.....%d\n", kes);
    uint8_t now_tile = m->now_tile;
    bool handnow = false;
    if(m->hutype == ZI_MO) { 
        handnow = true;
        now_tile = 0;
    }
    vector<uint8_t> ankes {};
    vector<uint8_t> elsekes {};
    vector<vector<uint8_t>> allkes;
    MJ_CPG_INFO *c = &m->cpg;
    for(uint8_t i=0; i<c->count; i++) {
        if(c->cpgs[i].type == GANG and c->cpgs[i].subtype == AN_GANG)
            ankes.push_back(c->cpgs[i].com[0]);
        else if(c->cpgs[i].type != CHI) 
            elsekes.push_back(c->cpgs[i].com[0]);
    }
    if(kes > ankes.size()) {
        allkes = getAllKeList(handnow ? &m->ti_hand_now : &m->ti_hand,
                              now_tile, kes, ankes);
        /*printf("$$$$$$$$$$$$$$$..........%d..", allkes.size());
        for(auto aaa : allkes) {
            for(auto bbb: aaa) {
                printf("%d ", bbb);
            }
            printf("\n");
        }*/
    }
    else if(kes == ankes.size()) 
        allkes.push_back(ankes);
    else
        return 0;
    if(allkes.size()==0)
        return 0;
    if(allkes.size()==1) 
        return fxv2ret(allkes[0], kes);

    vector<vector<uint8_t>> silian {};
    vector<vector<uint8_t>> sanlian {};
    vector<vector<uint8_t>> tongke {};

    for(auto kets : allkes) {
        vector<uint8_t> kelist = kets;
        catvv(kelist, elsekes);
        sort(kelist.begin(), kelist.end());
        if(kes==4 and kelist[kelist.size()-1]-kelist[0]==kes-1) {
            return fxv2ret(kets, kes);
        }
        if(kelist.size()==4) {
            if(kelist[3] - kelist[0] == 3)
                silian.push_back(kets);
            if(kelist[2]-kelist[0]==2 or kelist[3]-kelist[1]==2)
                sanlian.push_back(kets);
        } else if(kelist.size()==3) {
            if(kelist[2]-kelist[0]==2)
                sanlian.push_back(kets);
        }
        vector<uint8_t> _tmps {};
        for(auto kk : kelist) 
            _tmps.push_back(kk%10);
        set<uint8_t> _tmpset(_tmps.begin(), _tmps.end());
        if(_tmpset.size() < kelist.size()) 
            tongke.push_back(kets);
    }
    if(silian.size()!=0) {
        return fxv2ret(silian[0], kes);
    }
    if(sanlian.size()!=0) {
        //Python代码中，这种情况直接返回sanlian[0]
        //这里补充了一个选择的逻辑，选占用癞子最少的返回
        Tiles *tc = handnow ? &m->ti_hand_now : &m->ti_hand;
        uint8_t best_idx = 0;
        int max_total_card = 0;
        for(uint8_t i=0; i<sanlian.size(); i++) {
            int total_card = 0;
            for(uint8_t j=0; j<kes; j++) 
                total_card+=tc->counter_noz.bucket[sanlian[i][j]-1];
            if(total_card>max_total_card) {
                best_idx = i;
                max_total_card = total_card;
            }
        }
        return fxv2ret(sanlian[best_idx], kes);
    }
    if(tongke.size()!=0) {
        return fxv2ret(tongke[0], kes);
    }
    return fxv2ret(allkes[0], kes);
}

vector<vector<uint8_t>> 
getAllKeList(Tiles *ti, uint8_t nowtile, uint8_t kes, vector<uint8_t> &ankes) {
    vector<vector<uint8_t>> res {};
    vector<uint8_t> new_hand {};
    for(uint8_t i=0; i<ti->counter_noz.bucket_len; i++) {
        if(ti->counter_noz.bucket[i]>0)
            new_hand.push_back(i+1);
    }

    vector<uint8_t> hand {};
    ti->getHandsNoZi(hand);
    vector<uint8_t> cpkes;
    vector<uint8_t> cphand;
    vector<uint8_t> rcom;
    vector<uint8_t> cp2hand;
    vector<uint8_t> cp2kes;
    vector<uint8_t> _com;

    /*printf("000000000000........");
    for(auto ccc : new_hand) {
        printf("%d ", ccc);
    }
    printf("\n");*/

    for (auto&& m : combinations(new_hand, kes - ankes.size())) {
        _com.clear();
        for (auto&& n : m ) 
            _com.push_back(n);

        /*printf("11111111111........");
        for(auto ccc : _com) {
            printf("%d ", ccc);
        }
        printf("\n");*/

        cpkes = ankes;
        cphand = hand;
        uint8_t lzcount = ti->laizi_count;

        for(uint8_t i=0; i<_com.size(); i++) {
            uint8_t t = _com[i];
            uint8_t count = ti->counter_noz.bucket[t-1];
            uint8_t rcount = count>3 ? 3 : count;
            if(lzcount < 3-rcount) break;
            remove_nv(cphand, t, rcount);
            lzcount -= (3-rcount);
            cpkes.push_back(t);
        }

        if(cpkes.size() != kes) continue;
        if(!hasHu_bu(cphand, lzcount, 35, nowtile)) 
            continue;
        if(nowtile==35) 
            lzcount++;
        else if(nowtile>0) 
            cphand.push_back(nowtile);
        bool isNotAppend = true;

        /*printf("WWWWWWWWWWWWWWW........");
        for(auto ccc : cphand) {
            printf("%d ", ccc);
        }
        printf("\n");*/

        vector<vector<uint8_t>> hlc = handListCom(cphand);
        for(uint8_t i=0; i<hlc.size(); i++) {
            rcom = hlc[i];
            cp2hand = cphand;
            cp2kes = cpkes;
            uint8_t lzcount2 = lzcount;
            bool addRCom = true;
            for(uint8_t j=0; j<rcom.size(); j++) {
                uint8_t r = rcom[j];
                uint8_t num = count(cp2hand.begin(), cp2hand.end(), r);
                uint8_t rcount = num>3 ? 3 : num;
                if(lzcount2 < 3-rcount) {
                    addRCom = false;
                    continue;
                }
                remove_nv(cp2hand, r, rcount);
                lzcount2 -= (3-rcount);
            }
            if(addRCom) {
                if(!hasHu_bu(cp2hand, lzcount2, 35, 0))
                    continue;
                catvv(cp2kes, rcom);
            }
            isNotAppend = false;
            res.push_back(cp2kes);
        }
        if(isNotAppend) {
            res.push_back(cpkes);
        }
    }
    return res;
}

vector<vector<uint8_t>> 
handListCom(vector<uint8_t> &hands) {
    vector<vector<uint8_t>> res {};
    set<uint8_t> shand(hands.begin(), hands.end());
    vector<uint8_t> _com {};
    for(uint8_t i=0; i<shand.size(); i++) {
        if((i+1)==(uint8_t)shand.size()) continue;
        for (auto&& m : combinations(shand, i+1)) {
            _com.clear();
            for (auto&& n : m ) 
                _com.push_back(n);
            res.push_back(_com);
        }
    }
    return res;
}

uint64_t 
fx_YiSeShuangLongHui(MJ_FX_INFO *m) {
    if(!m) return 0;
    if(fx_QingYiSe(m)==0) 
        return 0;

    Tiles *ti = &m->ti_hand_now;

    MJ_COUNTER *cnz = &ti->counter_noz;
    vector<uint8_t> new_hand {};
    for(uint8_t i=0; i<cnz->bucket_len; i++) {
        uint8_t tcnt = cnz->bucket[i];
        if(tcnt>0) {
            for(uint8_t o=0; o<tcnt; o++)
                new_hand.push_back((i+1)%10); 
        }
    }
    uint8_t lzcount = ti->laizi_count;

    vector<uint8_t> shuang_long {1, 1, 2, 2, 3, 3, 5, 5, 7, 7, 8, 8, 9, 9};
    for(uint8_t i=0; i<new_hand.size(); i++) {
        uint8_t t = new_hand[i];
        if(!findv(shuang_long, t))
            return 0;
        remove_nv(shuang_long, t, 1);
    }
    if(shuang_long.size() != lzcount)
        return 0;
    return 1;
}

uint64_t
fx_QuanShuangKe(MJ_FX_INFO *m) {
    if(fx_DuiDuiHu(m)==0)
        return 0;
    Tiles *ti = &m->ti_all;
    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    for(uint8_t i=0; i<hands.size(); i++) {
        uint8_t t = hands[i];
        if(t>=30) return 0;
        if(t%2>0) return 0;
    }
    return 1;
}

uint64_t
fx_QuanDaiWu(MJ_FX_INFO *m) {
    if(!m) return 0;
    MJ_CPG_INFO *c = &m->cpg;
    for(int i=0; i<c->count; i++) {
        vector<uint8_t> pat(c->cpgs[i].com, c->cpgs[i].com+4);
        if(!findv(pat, 5) and !findv(pat, 15) and !findv(pat, 25)) 
            return 0;
    }
    Tiles *ti = &m->ti_hand_now;
    uint8_t lzcount = ti->laizi_count;
    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    for(uint8_t i=0; i<hands.size(); i++) {
        uint8_t t = hands[i];
        if(t%10<3 or t%10>7)
            return 0;
    }
    vector<uint8_t> fives {5,15,25};

    for(uint8_t i=0; i<3; i++) {
        uint8_t five = fives[i];
        if(!findv(hands, five)) 
            continue;
        for(uint8_t j=0; j<3; j++) {
            int8_t adj = -2+j;
            while(findv(hands, five+adj) and findv(hands, five+adj+1) and 
                  findv(hands, five+adj+2)) {
                remove_nv(hands, five+adj, 1);
                remove_nv(hands, five+adj+1, 1);
                remove_nv(hands, five+adj+2, 1);
            }
        }
    }
    vector<uint8_t> not_five {};
    for(uint8_t i=0; i<hands.size(); i++) {
        uint8_t t = hands[i];
        if(findv(fives, t))
            continue;
        not_five.push_back(t);
    }
    while(not_five.size()!=0) {
        uint8_t tile = not_five.back();
        uint8_t start;
        not_five.pop_back();
        if(tile%10<5) 
            start = tile;
        else 
            start = tile/10*10+5;
        for(uint8_t i=0; i<3; i++) {
            uint8_t si = start+i;
            if(findv(hands, si)) {
                remove_nv(hands, si, 1);
                if(start+i != tile and findv(not_five, si)) 
                    remove_nv(not_five, si, 1);
            } else {
                if(lzcount>0) lzcount--;
                else return 0;
            }
        }
    }
    return hasHu_bu(hands, lzcount, 35, 0) ? 1 : 0;
}

uint64_t
fx_DaYuWu(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_all;
    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    for(uint8_t i=0; i<hands.size(); i++) {
        uint8_t t = hands[i];
        if(t>=30) return 0;
        if(t%10<=5) return 0;
    }
    return 1;
}

uint64_t
fx_XiaoYuWu(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_all;
    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    for(uint8_t i=0; i<hands.size(); i++) {
        uint8_t t = hands[i];
        if(t>=30) return 0;
        if(t%10>=5) return 0;
    }
    return 1;
}

uint64_t
fx_Bian(MJ_FX_INFO *m) {
    if(!m) return 0;

    uint8_t hutile = m->now_tile;
    if(hutile == 0) return 0;
    if(hutile>30 and hutile!=35) return 0;

    Tiles *ti = &m->ti_hand_now;

    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    uint8_t lzcount = ti->laizi_count;

    if(hutile%10 == 7 and hutile!=35) {
        if(!findv(hands, hutile + 2))
            return 0;
        remove_nv(hands, hutile, 1);
        remove_nv(hands, hutile+2, 1);
        if(findv(hands, hutile + 1))
            remove_nv(hands, hutile+1, 1);
        else {
            if(lzcount==0) return 0;
            lzcount--;
        }
        return hasHu_bu(hands, lzcount, 35, 0) ? 1 : 0;
    } else if(hutile%10 == 3 and hutile!=35) {
        if(!findv(hands, hutile - 2))
            return 0;
        remove_nv(hands, hutile, 1);
        remove_nv(hands, hutile-2, 1);
        if(findv(hands, hutile - 1))
            remove_nv(hands, hutile-1, 1);
        else {
            if(lzcount==0) return 0;
            lzcount--;
        }
        return hasHu_bu(hands, lzcount, 35, 0) ? 1 : 0;
    } else if(hutile == 35) {
        uint8_t aa[6][2] {{1,2}, {8,9}, {11,12}, {18,19}, {21,22}, {28,29}}; 
        for(uint8_t i=0; i<6; i++) {
            uint8_t arr0 = aa[i][0];
            uint8_t arr1 = aa[i][1];
            if(!findv(hands, arr0) or !findv(hands, arr1))
                continue;
            vector<uint8_t> copyhands = hands;
            uint8_t copylz = lzcount;
            remove_nv(copyhands, arr0, 1);
            remove_nv(copyhands, arr1, 1);
            copylz--;
            if(hasHu_bu(copyhands, copylz, 35, 0))
                return 1;
        }
    }
    return 0;
}

uint64_t
fx_Kan(MJ_FX_INFO *m) {
    if(!m) return 0;

    uint8_t hutile = m->now_tile;
    if(hutile == 0) return 0;
    if(hutile%10==1 or hutile%10==9) return 0;
    if(hutile>=30 and hutile!=35) return 0;

    Tiles *ti = &m->ti_hand_now;

    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);

    if(!ti->isLaiZi(hutile)) {
        if(findv(hands, hutile+1) or findv(hands, hutile-1)) {
            vector<uint8_t> cphand = hands;
            uint8_t lzcount = ti->laizi_count;
            remove_nv(cphand, hutile, 1);
            if(findv(hands, hutile-1))
                remove_nv(cphand, hutile-1, 1);
            else {
                if(lzcount>0) lzcount--;
                else return 0;
            }
            if(findv(hands, hutile+1))
                remove_nv(cphand, hutile+1, 1);
            else {
                if(lzcount>0) lzcount--;
                else return 0;
            }
            if(hasHu_bu(cphand, lzcount, 35, 0))
                return 1;
        }
    } else {
        for(uint8_t i=0; i<hands.size(); i++) {
            uint8_t ht = hands[i];
            if(ht%10>7) continue;
            vector<uint8_t> cphand = hands;
            uint8_t lzcount = ti->laizi_count;
            remove_nv(cphand, ht, 1);
            if(findv(cphand, ht+2))
                remove_nv(cphand, ht+2, 1);
            else {
                if(lzcount>0) lzcount--;
                else continue;
            }
            if(lzcount>0) lzcount--;
            else continue;
            if(hasHu_bu(cphand, lzcount, 35, 0))
                return 1;
        }
    } 
    return 0;
}

uint64_t
fx_DanDiao(MJ_FX_INFO *m) {
    if(!m) return 0;

    Tiles *ti = &m->ti_hand;

    uint8_t hutile = m->now_tile;
    if(!ti->isLaiZi(hutile)) {
        if(ti->counter_noz.bucket[hutile-1]==0) 
            return 0;
        vector<uint8_t> hands {};
        ti->getHands(hands);
        remove_nv(hands, hutile, 1);
        return hasHu_bu(hands, 2, 31, 0) ? 1 : 0;
    } else {
        vector<uint8_t> hands {};
        ti->getHands(hands);
        set<uint8_t> tss(hands.begin(), hands.end());
        for(auto t:tss) {
            vector<uint8_t> cphand = hands;
            remove_nv(cphand, t, 1);
            if(hasHu_bu(cphand, 2, 31, 0))
                return 1;
        }
    }
    return 0;
}

uint64_t
fx_LaoShaoPei(MJ_FX_INFO *m) {
    if(!m) return 0;

    Tiles *ti = &m->ti_hand_now;

    vector<vector<uint8_t>> shunTiles {
        {1, 2, 3, 7, 8, 9},
        {11, 12, 13, 17, 18, 19},
        {21, 22, 23, 27, 28, 29},
        {0}
    };
    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    for(auto shun : shunTiles) {
        vector<uint8_t> cphand = hands;
        uint8_t lzcount = ti->laizi_count;
        bool hasShun = true;
        uint8_t le_three_c = 0;
        uint8_t ge_seven_c = 0;
        for (auto tile : shun) {
            if(!findv(cphand, tile)) {
                if(lzcount==0) {
                    hasShun = false;
                    break;
                }
                lzcount--;
                continue;
            }
            if(tile%10 <= 3) le_three_c++;
            if(tile%10 >= 7) ge_seven_c++;
            remove_nv(cphand, tile, 1);
        }
        if(!hasShun or le_three_c==0 or ge_seven_c==0)
            continue;
        uint8_t nt = m->now_tile;
        if(findv(cphand, nt))
            remove_nv(cphand, nt, 1);
        else
            nt = 0;

        if(hasHu_bu(cphand, lzcount, 35, nt)) {
            if(shun.size()==1) return 0;
            return fxv2ret(shun, shun.size());
        }
    }
    return 0;
}

uint64_t
fx_ShuangTongKe(MJ_FX_INFO *m) {
    if(!m) return 0;
    vector<uint8_t> cpgtiles {};
    for(int i=0; i<m->cpg.count; i++)
        cpgtiles.push_back(m->cpg.cpgs[i].tile);

    Tiles *ti = &m->ti_all_gang4to3;

    vector<uint8_t> colors {};
    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    for(auto t : hands) {
        if(findv(colors, t/10))
            continue;
        colors.push_back(t/10);
    }
    if(colors.size()==1) return 0;
    uint8_t uselz = 0;
    uint8_t lzcount = ti->laizi_count;
    set<uint8_t> handset(hands.begin(), hands.end());

    vector<vector<uint8_t>> tongkes {};
    vector<uint8_t> haskes {};

    for(auto tile: handset) {
        if(tile>30 or findv(haskes, tile)) continue;
        if(tile/10 == colors[1]) continue;
        vector<uint8_t> cphand = hands;
        uint8_t tile1 = 10*colors[1] + tile%10;
        if(ti->counter_noz.bucket[tile1-1]<1)
            continue;
        vector<uint8_t> tmpv {tile, tile1};
        for(auto t : tmpv) {
            uint8_t tile_c = ti->counter_noz.bucket[t-1];
            uselz += (tile_c>=3 ? 0 : 3-tile_c);
            remove_nv(cphand, t, tile_c>=3? 3 : tile_c);
        }
        if(uselz > lzcount) {
            uselz = 0;
            continue;
        }
        for(auto p : cpgtiles) {
            if(!findv(cphand, p) or count(cphand.begin(), cphand.end(), p)<3)
                continue;
            remove_nv(cphand, p, 3);
        }
        if(hasHu_bu(cphand, lzcount-uselz, 35, 0)) {
            haskes.push_back(tile);
            haskes.push_back(tile1);
            tongkes.push_back(tmpv);
        }
        uselz = 0;
    }
    if(tongkes.size()!=0) {
        vector<uint8_t> tmpv {};
        for(auto tks : tongkes) {
            tmpv.push_back(tks[0]);
            tmpv.push_back(tks[1]);
        }
        return fxv2ret(tmpv, tmpv.size());
    }
    return 0;
}

uint64_t
fx_YiBanGao(MJ_FX_INFO *m) {
    if(!m) return 0;

    Tiles *ti = &m->ti_hand_now;

    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    uint8_t uselz = 0;
    uint8_t lzcount = ti->laizi_count;
    set<uint8_t> handset(hands.begin(), hands.end());
    vector<uint8_t> cphand;
    for(auto tile: handset) {
        if(tile>30) continue;
        cphand = hands;
        uint8_t tile1, tile2;
        if(tile%10 <= 7) {
            tile1 = tile + 1;
            tile2 = tile + 2;
        } else if(tile%10 == 8) {
            tile1 = tile + 1;
            tile2 = tile - 1;
        } else {
            tile1 = tile - 1;
            tile2 = tile - 2;
        }
        vector<uint8_t> tmpv {tile, tile1, tile2};
        for(auto t : tmpv) {
            uint8_t tile_c = ti->counter_noz.bucket[t-1];
            uselz += (tile_c>=2 ? 0 : 2-tile_c);
            remove_nv(cphand, t, tile_c>=2 ? 2 : tile_c);
        }
        if(uselz > lzcount) {
            uselz = 0;
            continue;
        }
        if(hasHu_bu(cphand, lzcount-uselz, 35, 0)) {
            return fxv2ret(tile, tile1, tile2);
        }
        uselz = 0;
    }
    return 0;
}

uint64_t
fx_LianLiu(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand_now;
    set<uint8_t> colors {};
    for(uint8_t i=WAN; i<TONG; i++) {
        if(ti->counter[i].n)
            colors.insert(i);
    }
    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    uint8_t uselz = 0;
    uint8_t lzcount = ti->laizi_count;
    for(auto color : colors) {
        for(uint8_t i=1; i<5; i++) {
            uint8_t start = color*10+i;
            vector<uint8_t> cphand = hands;
            for(uint8_t j=0; j<6; j++) {
                uint8_t tile = start + j;
                if(findv(cphand, tile)) {
                    remove_nv(cphand, tile, 1);
                } else {
                    uselz++;
                }
            }
            if(uselz > lzcount) {
                uselz = 0;
                continue;
            }
            if(hasHu_bu(cphand, lzcount-uselz, 35, 0)) {
                return fxv2ret(start);
            }
            uselz = 0;
        }
    }
    return 0;
}

uint64_t
fx_SanJieGao(MJ_FX_INFO *m) {
    if(!m) return 0;
    vector<uint8_t> cpgtiles {};
    for(int i=0; i<m->cpg.count; i++)
        cpgtiles.push_back(m->cpg.cpgs[i].tile);

    Tiles *ti = &m->ti_all_gang4to3;

    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    uint8_t uselz = 0;
    uint8_t lzcount = ti->laizi_count;
    set<uint8_t> handset(hands.begin(), hands.end());
    for(auto tile: handset) {
        if(tile>30) continue;
        vector<uint8_t> cphand = hands;
        uint8_t tile1, tile2;
        if(tile%10 <= 7) {
            tile1 = tile + 1;
            tile2 = tile + 2;
        } else if(tile%10 == 8) {
            tile1 = tile + 1;
            tile2 = tile - 1;
        } else {
            tile1 = tile - 1;
            tile2 = tile - 2;
        }

        if(!findv(hands, tile1) or !findv(hands, tile2))
            continue;

        vector<uint8_t> tmpv {tile, tile1, tile2};
        for(auto t : tmpv) {
            uint8_t tile_c = ti->counter_noz.bucket[t-1];
            uselz += (tile_c>=3 ? 0 : 3-tile_c);
            remove_nv(cphand, t, tile_c>=3 ? 3 : tile_c);
        }
        if(uselz > lzcount) {
            uselz = 0;
            continue;
        }
        for(auto p : cpgtiles) {
            if(!findv(cphand, p) or count(cphand.begin(), cphand.end(), p)<3)
                continue;
            remove_nv(cphand, p, 3);
        }
        if(hasHu_bu(cphand, lzcount-uselz, 35, 0)) {
            return fxv2ret(tile, tile1, tile2);
        }
        uselz = 0;
    }
    return 0;
}

uint64_t
fx_SiJieGao(MJ_FX_INFO *m) {
    if(!m) return 0;
    vector<uint8_t> cpgtiles {};
    for(int i=0; i<m->cpg.count; i++)
        cpgtiles.push_back(m->cpg.cpgs[i].tile);

    Tiles *ti = &m->ti_all_gang4to3;

    vector<uint8_t> hands {};
    ti->getHandsNoZi(hands);
    uint8_t uselz = 0;
    uint8_t lzcount = ti->laizi_count;
    set<uint8_t> handset(hands.begin(), hands.end());
    for(auto tile: handset) {
        if(tile>30) continue;
        vector<uint8_t> cphand = hands;
        uint8_t tile1, tile2, tile3;
        if(tile%10 <= 6) {
            tile1 = tile + 1;
            tile2 = tile + 2;
            tile3 = tile + 3;
        } else if(tile%10 == 7) {
            tile1 = tile + 1;
            tile2 = tile - 1;
            tile3 = tile + 2;
        } else if(tile%10 == 8) {
            tile1 = tile + 1;
            tile2 = tile - 1;
            tile3 = tile - 2;
        } else {
            tile1 = tile - 1;
            tile2 = tile - 2;
            tile3 = tile - 3;
        }

        if(!findv(hands, tile1) or
           !findv(hands, tile2) or
           !findv(hands, tile3))
            continue;

        vector<uint8_t> tmpv {tile, tile1, tile2, tile3};
        for(auto t : tmpv) {
            uint8_t tile_c = ti->counter_noz.bucket[t-1];
            uselz += (tile_c>=3 ? 0 : 3-tile_c);
            remove_nv(cphand, t, tile_c>=3 ? 3 : tile_c);
        }
        if(uselz > lzcount) {
            uselz = 0;
            continue;
        }
        for(auto p : cpgtiles) {
            if(!findv(cphand, p) or count(cphand.begin(), cphand.end(), p)<3)
                continue;
            remove_nv(cphand, p, 3);
        }
        if(hasHu_bu(cphand, lzcount-uselz, 35, 0)) {
            return fxv2ret(tile, tile1, tile2, tile3);
        }
        uselz = 0;
    }
    return 0;
}

uint64_t
fx_ShiErJinChai(MJ_FX_INFO *m) {
    if(!m) return 0;
    uint8_t gang = 0;
    for(int i=0; i<m->cpg.count; i++) {
        if(m->cpg.cpgs[i].type == GANG)
            gang++;
    }
    return gang==3 ? 1 : 0;
}

uint64_t
fx_BaiWanDan(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_all;
    uint8_t all = 0;
    vector<uint8_t> hands {};
    ti->getHands(hands);
    for(auto t : hands) {
        if(t>10) continue;
        all+=t;
    }
    return all>=100 ? 1 : 0;
}

uint64_t 
fx_DanDiaoHz(MJ_FX_INFO *m) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand;
    if(ti->tiles_len==1 and m->now_tile==35 and ti->tiles[0]==35)
        return 1;
    return 0;
}

uint64_t 
fx_SiAnKe(MJ_FX_INFO *m) {
    if(!m) return 0;
    return hasAnKe(m, 4);
}

uint64_t 
fx_SanAnKe(MJ_FX_INFO *m) {
    if(!m) return 0;
    return hasAnKe(m, 3);
}

uint64_t 
fx_ShuangAnKe(MJ_FX_INFO *m) {
    if(!m) return 0;
    return hasAnKe(m, 2);
}

uint64_t 
rm_WuKui(MJ_FX_INFO *m, uint64_t ret_data) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand;
    uint8_t wub[2] {4,6};
    vector<uint8_t> hand {};
    ti->getHands(hand);
    for(uint8_t i=0; i<2; i++) {
        if(ti->findTile(wub[i]))
            remove_nv(hand, wub[i], 1);
        else 
            remove_nv(hand, 35, 1);
    }
    vector<uint8_t> lz {35};
    assignMFI(m, hand, lz, 0, m->que, &m->cpg, m->hutype);
    return 1;
}

uint64_t 
rm_LaoShao(MJ_FX_INFO *m, uint64_t ret_data) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand;
    vector<uint8_t> lz {35};
    vector<uint8_t> hand {};
    ti->getHands(hand);
    uint8_t nt = m->now_tile;
    vector<uint8_t> retv {};
    fxret2v(ret_data, retv);
    for(int i=0; i<6; i++) {
        uint8_t t = retv[i];
        if(_hand_nt(hand, nt, t)==0) {
            assignMFI(m, hand, lz, nt, m->que, &m->cpg, m->hutype);
            return 0;
        }
    }
    assignMFI(m, hand, lz, nt, m->que, &m->cpg, m->hutype);
    return 1;
}

uint64_t 
rm_YiBanGao(MJ_FX_INFO *m, uint64_t ret_data) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand;
    vector<uint8_t> lz {35};
    vector<uint8_t> hand {};
    ti->getHands(hand);
    uint8_t nt = m->now_tile;
    vector<uint8_t> retv {};
    fxret2v(ret_data, retv);
    for(uint8_t i=0; i<2; i++) {
        for(uint8_t j=0; j<3; j++) {
            uint8_t t = retv[j];
            if(_hand_nt(hand, nt, t)==0) {
                assignMFI(m, hand, lz, nt, m->que, &m->cpg, m->hutype);
                return 0;
            }
        }
    }
    assignMFI(m, hand, lz, nt, m->que, &m->cpg, m->hutype);
    return 1;
}

uint64_t 
rm_LianLiu(MJ_FX_INFO *m, uint64_t ret_data) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand;
    vector<uint8_t> lz {35};
    vector<uint8_t> hand {};
    ti->getHands(hand);
    uint8_t nt = m->now_tile;
    vector<uint8_t> retv {};
    fxret2v(ret_data, retv);
    for(uint8_t i=0; i<6; i++) {
        uint8_t t = retv[0] + i;
        if(_hand_nt(hand, nt, t)==0) {
            assignMFI(m, hand, lz, nt, m->que, &m->cpg, m->hutype);
            return 0;
        }
    }
    assignMFI(m, hand, lz, nt, m->que, &m->cpg, m->hutype);
    return 1;
}

uint64_t 
rm_DanDiao(MJ_FX_INFO *m, uint64_t ret_data) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand;
    vector<uint8_t> hand {};
    ti->getHands(hand);
    hand.push_back(m->now_tile);
    vector<uint8_t> lz {35};
    MJ_HU_TYPE t = m->hutype;
    assignMFI(m, hand, lz, 0, m->que, &m->cpg);
    m->hutype = t;
    return 1;
}

uint64_t 
rm_KeTiles(MJ_FX_INFO *m, vector<uint8_t> &ts) {
    if(!m) return 0;
    Tiles *ti = &m->ti_hand;
    vector<uint8_t> lz {35};
    vector<uint8_t> hand {};
    ti->getHands(hand);
    MJ_CPG_INFO cpg;
    vector<uint8_t> remaintiles = ts;
    cpg.count = 0;
    for(uint8_t i=0; i<m->cpg.count; i++) {
        uint8_t tile = m->cpg.cpgs[i].tile;
        if(!findv(remaintiles, tile)) {
            cpg.cpgs[cpg.count] = m->cpg.cpgs[i];
            cpg.count++;
            continue;
        }
        remove_nv(remaintiles, tile, 1);
    }
    uint8_t nt = m->now_tile;
    for(auto t : remaintiles) {
        for(uint8_t i=0; i<3; i++) {
            if(_hand_nt(hand, nt, t)==0) {
                assignMFI(m, hand, lz, nt, m->que, &cpg, m->hutype);
                return 0;
            }
        }
    }
    assignMFI(m, hand, lz, nt, m->que, &cpg, m->hutype);
    return 1;
}

uint64_t 
rm_TongKeTiles(MJ_FX_INFO *m, vector<uint8_t> &ketiles, uint64_t tongkes) {
    if(!m) return 0;
    vector<uint8_t> lz {35};
    vector<uint8_t> retv {};
    fxret2v(tongkes, retv);
    vector<uint8_t> hand {};
    Tiles *ti = &m->ti_hand;
    ti->getHands(hand);
    MJ_CPG_INFO cpg;
    vector<uint8_t> remaintiles {};

    for(uint8_t tk=0; tk<retv.size()/2; tk++) {
        remaintiles.clear();
        for(uint8_t i=0; i<2; i++) {
            uint8_t tong = retv[tk*2 + i];
            if(!findv(ketiles, tong)) {
                remaintiles.push_back(tong);
            }
        }
        cpg.count = 0;
        for(uint8_t i=0; i<m->cpg.count; i++) {
            uint8_t tile = m->cpg.cpgs[i].tile;
            if(!findv(remaintiles, tile)) {
                cpg.cpgs[cpg.count] = m->cpg.cpgs[i];
                cpg.count++;
                continue;
            }
            remove_nv(remaintiles, tile, 1);
        }
        uint8_t nt = m->now_tile;
        vector<uint8_t> cptile = hand;
        bool isbreak = false;
        for(auto ke : remaintiles) {
            for(uint8_t i=0; i<3; i++) {
                if(_hand_nt(cptile, nt, ke)==0) {
                    isbreak = true;
                    break;
                }
            }
        }
        if(!isbreak) {
            uint8_t ret = hasHu(cptile, nt);
            if(ret) {
                for(auto ke : remaintiles) {
                    for(uint8_t i=0; i<3; i++) 
                        _hand_nt(hand, nt, ke);

                }
                assignMFI(m, hand, lz, nt, m->que, &cpg, m->hutype);
                return 1;
            }
        }
    }
    return 0;
}

